package com.neusoft.databus.agent.parser.modbus;

import java.util.Arrays;

import org.springframework.util.StringUtils;

import com.neusoft.bizcore.web.utils.SpringUtil;
import com.neusoft.databus.agent.config.DatabusAgentProperties;
import com.neusoft.databus.common.bean.MetricBean;
import com.neusoft.databus.common.utils.DigitalUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * Modbus RTU parser<br>
 *
 * @author sunchf
 * @date 2019年1月7日 下午3:56:52
 */
@Slf4j
public class ModBusRTUParser extends ModBusParser {

    private final DatabusAgentProperties databusAgentProperties;

    public ModBusRTUParser() {
        this.databusAgentProperties = SpringUtil.getBean(DatabusAgentProperties.class);
    }

    @Override
    public int getResponseHeaderLength() {
        return 3;
    }

    @Override
    public byte[] generateReq(String slave, MetricBean metricBean) {
        final String commandCode = metricBean.getCommand();
        return this.generateReq(slave, commandCode);
    }

    public byte[] generateReq(String slave, String commandCode) {
        if (StringUtils.isEmpty(commandCode) || StringUtils.isEmpty(commandCode.trim())) {
            return null;
        }
        final byte[] data = DigitalUtils.hexStringToBytes(slave + commandCode);
        final byte[] req = DigitalUtils.hexStringToBytes(slave + commandCode + DigitalUtils.crc16(data));
        return req;
    }

    @Override
    public int expectedResDataLength(byte[] req) {
        final byte functionCode = req[1];
        final int registerSize = DigitalUtils.bytesToUShort(new byte[] {req[4], req[5] }, 0);
        //默认按功能码03,04处理
        int expected = this.getResponseHeaderLength() + (registerSize * 2) + 2;
        switch (functionCode) {
        case 0x01:
        case 0x02:
            expected = this.getResponseHeaderLength() + ((Double) Math.ceil(registerSize / 8.0)).intValue() + 2;
            break;
        default:
            break;
        }
        return expected;
    }

    @Override
    public boolean validateResult(byte[] data) {
        if (null == data) {
            return false;
        }
        if (!this.databusAgentProperties.getModbus().isRtuCrcCheck()) {
            return true;
        }
        final String caculatedCRC = DigitalUtils.crc16(Arrays.copyOf(data, data.length - 2));
        final String carriedCRC =
                DigitalUtils.bytesToHexString(new byte[] {data[data.length - 2], data[data.length - 1] });

        if (caculatedCRC.equalsIgnoreCase(carriedCRC)) {
            return true;
        } else {
            ModBusRTUParser.log.warn("CRC校验错误,返回值{},计算值{}", carriedCRC, caculatedCRC);
            return false;
        }
    }

}
